package com.bestcem.xm.om.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.bp.pay.grpc.v1.services.Order;
import com.bestcem.bp.xm.user.grpc.v1.services.Organization;
import com.bestcem.bp.xm.user.grpc.v1.services.User;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.enums.AuthErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ReqErrorCodeEnum;
import com.bestcem.xm.common.core.uitls.DateUtil;
import com.bestcem.xm.common.core.uitls.GrpcDateUtil;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.bestcem.xm.om.config.properties.UserSettingProperties;
import com.bestcem.xm.om.constant.CommonConstant;
import com.bestcem.xm.om.constant.OrderConstant;
import com.bestcem.xm.om.constant.RedisKeyConstant;
import com.bestcem.xm.om.dao.OmUserPackDao;
import com.bestcem.xm.om.entity.UserPack;
import com.bestcem.xm.om.entity.readonly.UserOrganization;
import com.bestcem.xm.om.enums.PackageTypeEnum;
import com.bestcem.xm.om.enums.SendChannelEnum;
import com.bestcem.xm.om.enums.SendStatusEnum;
import com.bestcem.xm.om.enums.pack.PaymentMethodEnum;
import com.bestcem.xm.om.grpc.client.OmOrgGrpcService;
import com.bestcem.xm.om.grpc.client.OmUserUserGrpcService;
import com.bestcem.xm.om.grpc.client.PaymentService;
import com.bestcem.xm.om.grpc.service.converter.OmPackageConverter;
import com.bestcem.xm.om.grpc.service.dto.OrderDTO;
import com.bestcem.xm.om.grpc.service.param.UpgradePackageParam;
import com.bestcem.xm.om.mq.dto.MsgDataDTO;
import com.bestcem.xm.om.service.OmMqService;
import com.bestcem.xm.om.service.OrderService;
import com.bestcem.xm.om.service.SmsService;
import com.bestcem.xm.om.service.email.JavaEmailSenderPool;
import com.bestcem.xm.om.util.EmailTemplateUtil;
import com.bestcem.xm.om.util.EmailUtil;
import com.bestcem.xm.om.util.SmsTemplateUtil;
import com.bestcem.xm.om.util.SycExecUtil;
import com.bestcem.xm.user.enums.OrderExtraDurationEnum;
import com.bestcem.xm.user.enums.OrderTypeEnum;
import com.bestcem.xm.user.enums.WechatPayStatusEnum;
import com.bestcem.xm.user.service.dto.order.UpgradePackDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.bestcem.xm.om.constant.RedisKeyConstant.USER_PACK_PERM;

/**
 * OrderServiceImpl
 *
 * @author zhangfeng <feng.zhang@idiaoyan.com>
 * @version v1.0
 * @date 2021/7/16 15:43
 */
@Slf4j
@Service("omOrderService")
public class OrderServiceImpl implements OrderService {

    @Resource
    private PaymentService paymentService;
    @Resource
    private OmOrgGrpcService omOrgGrpcService;
    @Resource
    private OmUserUserGrpcService omUserUserGrpcService;
    @Resource
    private OmUserPackDao omUserPackDao;

    @Value("${app.xm.is-baseline: false}")
    private boolean isBaseline;

    private String packageEmailPrefix;

    @Resource
    private JavaEmailSenderPool javaEmailSenderPool;
    @Resource
    private SycExecUtil sycExecUtil;

    @Resource
    private SmsService smsService;

    @Resource
    private RedisService redisUtil;

    @Resource
    private OmMqService omMqService;

    @Value("${app.user.server.xm_server_host:xm-test.bestcem.com}")
    private String xmServerHost;

    @Value("${app.user.server.protocol:http}")
    private String serverProtocol;

    @Value("${spring.profiles.active:prod}")
    private String env;

    @Autowired
    private UserSettingProperties settingProperties;

    private static final String PACK_TYPE = "pack_type";
    private static final String UPGRADE_START_DATE = "upgrade_start_date";
    private static final String UPGRADE_END_DATE = "upgrade_end_date";
    private static final String DURATION = "duration";

    private static final String ORDER_MANAGER_URL_SUFFIX = "/company/order/account";

    /**
     * 初始化套餐邮件前缀
     */
    @PostConstruct
    public void init() {
        packageEmailPrefix = serverProtocol + "://www." + xmServerHost;
    }

    /**
     * 根据升级起始日期获取升级开始日期
     *
     * @param duration       购买时长
     * @param upgradeEndDate
     * @return
     */
    private LocalDateTime getUpgradeStartDate(int duration, LocalDateTime upgradeEndDate) {
        if (duration != 0) {
            return upgradeEndDate.minusYears(duration);
        }
        return null;
    }

    /**
     * 套餐升级
     * duration_unit: 购买时间单位，默认为年，可设置月或者天
     * activity_code: 区分不同的购买操作，详见 UPGRADE_PACKAGE_LOGIC_MAP
     * python ref: apps_mysql.user.util.utils.upgrade_package
     *
     * @param orderNo
     * @return
     */
    @Override
    public ServiceResult<String> upgradePackage(String orderNo) {
        try {
            // 订单前置校验
            OrderDTO orderDTO = paymentService.getOrderStatus(orderNo);
            UpgradePackageParam param = OmPackageConverter.orderDto2UpgradePackageParam(orderDTO);
            // 订单类型不等于倍市得版本购买，支付方式不是微信支付
            if (!orderDTO.getType().equals(OrderTypeEnum.ORDER_TYPE_BESTCEM_PURCHASE.getType()) ||
                    !orderDTO.getPayMethod().equals(PaymentMethodEnum.PAYMENT_METHOD_WECHAT.getType())) {
                return ServiceResult.fail(ReqErrorCodeEnum.PARAM_FORMAT, String.format("[om]upgradePackage order_id[%s] is error", orderNo));
            }
            // 订单不是已支付状态
            if (!orderDTO.getStatus().equals(WechatPayStatusEnum.WECHAT_PAY_STATUS_PAID.getType())) {
                return ServiceResult.fail("订单未支付完成");
            }
            // 设置租户订单升级缓存，这里如果设置成功则执行，否则为已执行过
            if (redisUtil.setIfAbsent(CommonConstant.USER_UPGRADE_ORDER + param.getOrderNo(), param.getOrgId(), 3600L, TimeUnit.SECONDS)) {
                Organization organization = omOrgGrpcService.getByIdOrCode(param.getOrgId());
                if (Objects.isNull(organization)) {
                    return ServiceResult.fail(AuthErrorCodeEnum.ORG_NOT_EXISTS, "公司不存在");
                }
                UserPack oldPack = omUserPackDao.getById(organization.getFormalPackageId());
                UserPack newPack;
                // 如果激活码为A001，则根据套餐名称和套餐类型查询旧套餐信息
                if (param.getActivityCode().equals(CommonConstant.ORDER_BUY_TYPE_TRIAL)) {
                    // 专业版体验的套餐名，单独处理, 类型是自定义套餐（专业版双十一特惠）
                    newPack = omUserPackDao.getByNameAndType(CommonConstant.TRIAL_1111_PACK_NAME, param.getPackageType());
                } else {
                    newPack = omUserPackDao.getByType(param.getPackageType());
                }
                if (log.isInfoEnabled()) {
                    log.info(String.format("[om]---pack upgrade: %s,%s, duration_unit=%s, activity_code=%s", newPack.getName(), newPack.getType(), param.getDurationUnit(), param.getActivityCode()));
                }
                // 查询租户系统管理员用户信息
                User adminUser = omUserUserGrpcService.getAdminUserByOrgId(param.getOrgId());
                UpgradePackDTO upgradePackDTO;
                // 根据激活码不同，执行不同的套餐升级方法
                // 双十一专业版体验
                if (param.getActivityCode().equals(CommonConstant.ORDER_BUY_TYPE_TRIAL)) {
                    upgradePackDTO = upgradePackageTrialLogic(oldPack, newPack, organization, param.getDuration(), param.getDurationUnit());
                    // 双十一高级版，专业版特惠购买
                } else if (param.getActivityCode().equals(CommonConstant.ORDER_BUY_TYPE_DISCOUNT)) {
                    upgradePackDTO = upgradePackageDiscountLogic(oldPack, newPack, organization, param.getDuration(), param.getDurationUnit());
                    // 默认购买
                } else if (param.getActivityCode().equals(CommonConstant.ORDER_BUY_TYPE_DEFAULT)) {
                    upgradePackDTO = upgradePackageLogic(oldPack, newPack, organization, adminUser, orderDTO, param.getDuration(), param.getDurationUnit());
                } else {
                    return ServiceResult.success();
                }
                // 无套餐升级操作，直接返回
                if (Objects.isNull(upgradePackDTO)) {
                    return ServiceResult.success();
                }
                if (log.isInfoEnabled()) {
                    log.info("[OM]套餐升级操作开始");
                }
                // 套餐升级
                UserOrganization org = new UserOrganization();
                org.setOrgId(organization.getId());
                org.setPackageId(upgradePackDTO.getPackageId());
                org.setPackageExpireTime(DateUtil.toLocalTime(upgradePackDTO.getExpireDate()));
                org.setTrialPackageId(upgradePackDTO.getTrialPackageId());
                org.setTrialExpireTime(DateUtil.toLocalTime(upgradePackDTO.getTrialExpireDate()));
                org.setFormalPackageId(upgradePackDTO.getFormalPackageId());
                org.setFormalExpireTime(DateUtil.toLocalTime(upgradePackDTO.getFormalExpireDate()));
                try {
                    omOrgGrpcService.updateOrganization(org);
                    // 租户修改套餐 通知java  todo 暂不通知mq
//                    if (StringUtils.isNotBlank(upgradePackDTO.getPackageId())) {
//                        omMqUtil.orgPackUpdate(organization.getId(), oldPack.getId(), newPack.getId());
//                    }
                } catch (Exception e) {
                    log.error(String.format("[OM]套餐升级grpc失败===%s===%s", organization.getId(), param.getOrderNo()));
                    redisUtil.del(CommonConstant.USER_UPGRADE_ORDER + param.getOrderNo());
                }
                // 邮件参数信息处理
                Date upgradeEndTime = null;
                if (Objects.nonNull(upgradePackDTO.getFormalExpireDate())) {
                    upgradeEndTime = upgradePackDTO.getFormalExpireDate();
                    log.info("[OM]套餐升级，升级到期日upgradePackDTO.getFormalExpireDate()={}", upgradeEndTime);
                } else if (Objects.nonNull(upgradePackDTO.getTrialExpireDate())) {
                    upgradeEndTime = upgradePackDTO.getTrialExpireDate();
                    log.info("[OM]套餐升级，升级到期日upgradePackDTO.getTrialExpireDate()={}", upgradeEndTime);
                } else {
                    upgradeEndTime = getExpireDate(new Date(), param.getDuration(), param.getDurationUnit());
                    log.info("[OM]套餐升级，升级到期日upgradePackDTO.getExpireDate()={}", upgradeEndTime);
                }
                String upgradeEndTimeStr = DateUtil.convertDteToString(upgradeEndTime, DateUtil.YYYY_MM_DD);
                String emailDurationUnit = StringUtils.isNotBlank(OrderExtraDurationEnum.getByType(param.getDuration())) ? OrderExtraDurationEnum.getByType(param.getDuration()) : "年";
                String emailDuration = param.getDuration() + emailDurationUnit;
                String key = organization.getInner() ? RedisKeyConstant.ORDER_EMAIL_CONF_TEST : RedisKeyConstant.ORDER_EMAIL_CONF_REAL;
                List<String> toEmails = getNotifyEmails(key);
                // 计算升级起始日期
                LocalDateTime upgradeStartDate = getUpgradeStartDate(param.getDuration(), DateUtil.toLocalTime(upgradeEndTime));
                String upgradeStartTimeStr = "";
                if (Objects.nonNull(upgradeStartDate)) {
                    upgradeStartTimeStr = DateUtil.formatString(upgradeStartDate, DateUtil.YYYY_MM_DD);
                } else {
                    upgradeStartTimeStr = DateUtil.convertDteToString(new Date(), DateUtil.YYYY_MM_DD);
                }
                notifyConfirmUpgradeByEmail(toEmails, organization, oldPack.getName(), newPack.getName(), emailDuration, param.getOrder(), adminUser, upgradeStartTimeStr, upgradeEndTimeStr);
                // 完成订单，修改订单状态
                try {
                    // 更新订单升级起始日
                    JSONObject extraJson = JSON.parseObject(orderDTO.getExtra());
                    extraJson.put(UPGRADE_START_DATE, upgradeStartTimeStr);
                    extraJson.put(UPGRADE_END_DATE, upgradeEndTimeStr);
                    paymentService.completeOrder(Order.newBuilder()
                            .setOrderNo(param.getOrderNo())
                            .setExtra(extraJson.toJSONString()).build());
                } catch (Exception e) {
                    log.error(String.format("[OM]套餐修改状态失败===%s===%s", organization.getId(), param.getOrder().getId()));
                    redisUtil.del(CommonConstant.USER_UPGRADE_ORDER + param.getOrderNo());
                }
                // 短信通知用户
                notifyCompanyPackageUpgradeBySms(organization.getAdminPhone(), newPack.getName(), organization.getId());
                // 修改用户show_version字段
                omUserUserGrpcService.updateShowGuideByOrgId(organization.getId(), true);
                // 删除套餐缓存
                redisUtil.del(String.format(USER_PACK_PERM, org.getOrgId()));
            }
            if (log.isInfoEnabled()) {
                log.info("[OM]套餐升级操作结束");
            }
        } catch (Exception e) {
            log.error("[OM] 套餐升级grpc接口调用失败，orderNo={},e={}", orderNo, e);
            return ServiceResult.fail("套餐升级失败");
        }
        return ServiceResult.success();
    }

    /**
     * 试用专业版一个月, 仅支持基础版和高级版购买
     *
     * @param oldPack
     * @param newPack
     * @param organization
     * @param duration
     * @param durationUnit
     */
    private UpgradePackDTO upgradePackageTrialLogic(UserPack oldPack, UserPack newPack, Organization organization, Integer duration, Integer durationUnit) {
        if (log.isInfoEnabled()) {
            log.info(String.format("trial pack upgrade: %s,%s, duration:%s, durationUnit:%s", newPack.getName(), newPack.getType(), duration, durationUnit));
        }
        //  过期时间
        Date expireDate = getExpireDate(new Date(), duration, durationUnit);
        UpgradePackDTO upgradePackDTO;
        if (PackageTypeEnum.FREE.getType().equals(oldPack.getType()) || PackageTypeEnum.FREE_TRIAL.getType().equals(oldPack.getType())) {
            // 基础版直接体验一个月专业版
            upgradePackDTO = new UpgradePackDTO();
            upgradePackDTO.setPackageId(newPack.getId());
            upgradePackDTO.setExpireDate(expireDate);
            upgradePackDTO.setTrialPackageId(newPack.getId());
            upgradePackDTO.setTrialExpireDate(expireDate);
        } else if (PackageTypeEnum.SENIOR.getType().equals(oldPack.getType())) {
            // 高级版，体验一个月专业版，同时高级版到期日延期一个月
            upgradePackDTO = new UpgradePackDTO();
            upgradePackDTO.setPackageId(newPack.getId());
            upgradePackDTO.setExpireDate(expireDate);
            upgradePackDTO.setTrialPackageId(newPack.getId());
            upgradePackDTO.setTrialExpireDate(expireDate);
            upgradePackDTO.setFormalExpireDate(getExpireDate(GrpcDateUtil.getDate(organization.getFormalExpireTime()), duration, durationUnit));
        }
        return null;
    }

    /**
     * 高级版和专业版四折特惠， 仅对基础班，仅限购买一次，仅能购买一年
     * 基础版用户：正在试用“专业版双十一套餐”，此时购买高级版/专业版。订单支付成功后，
     * 正式套餐会自动变更为用户购买的版本，但此时生效的还是试用套餐。正式套餐的到期日=1年+剩余试用时间。
     * 基础版用户：没有试用“专业版双十一套餐”，此时购买高级版/专业版。订单支付成功后，
     * 正式套餐会自动变更为用户购买的版本，正式套餐立即生效，正式套餐的到期日=购买时长。
     * python ref:apps_mysql.user.util.utils.upgrade_package_discount_logic
     *
     * @param oldPack
     * @param newPack
     * @param organization
     * @param duration
     * @param durationUnit
     * @return
     */
    private UpgradePackDTO upgradePackageDiscountLogic(UserPack oldPack, UserPack newPack, Organization organization, Integer duration, Integer durationUnit) {

        if (log.isInfoEnabled()) {
            log.info(String.format("discount pack upgrade: %s,%s, duration:%s, durationUnit:%s", newPack.getName(), newPack.getType(), duration, durationUnit));
        }
        UpgradePackDTO upgradePackDTO;
        UserPack trialPack = null;
        if (StringUtils.isNotBlank(organization.getTrialPackageId())) {
            trialPack = omUserPackDao.getById(organization.getTrialPackageId());
        }
        if (PackageTypeEnum.FREE.getType().equals(oldPack.getType()) || PackageTypeEnum.FREE_TRIAL.getType().equals(oldPack.getType())) {
            upgradePackDTO = new UpgradePackDTO();
            if (Objects.nonNull(trialPack) && trialPack.getName().equals(CommonConstant.TRIAL_1111_PACK_NAME)
                    && Objects.nonNull(organization.getTrialExpireTime())
                    && GrpcDateUtil.getDate(organization.getTrialExpireTime()).after(new Date())) {
                Date formalPackExpireDt = getExpireDate(GrpcDateUtil.getDate(organization.getTrialExpireTime()), duration, durationUnit);
                upgradePackDTO.setFormalPackageId(newPack.getId());
                upgradePackDTO.setFormalExpireDate(formalPackExpireDt);
            } else {
                Date formalPackExpireDt = getExpireDate(new Date(), duration, durationUnit);
                upgradePackDTO.setPackageId(newPack.getId());
                upgradePackDTO.setExpireDate(formalPackExpireDt);
                upgradePackDTO.setFormalPackageId(newPack.getId());
                upgradePackDTO.setFormalExpireDate(formalPackExpireDt);
            }
        }
        return null;
    }

    /**
     * 默认套餐购买
     * 正常套餐购买逻辑
     * 购买双十一体验版的，后全款购买的用户
     * 正式套餐会自动变更为用户购买的版本，但此时生效的还是试用套餐。正式套餐的到期日=1年+剩余试用时间。
     *
     * @param oldPack
     * @param newPack
     * @param organization
     * @param adminUser
     * @param orderInfo
     * @param duration
     * @param durationUnit
     * @return
     */
    private UpgradePackDTO upgradePackageLogic(UserPack oldPack, UserPack newPack, Organization organization, User adminUser, OrderDTO orderInfo, Integer duration, Integer durationUnit) {
        if (log.isInfoEnabled()) {
            log.info(String.format("[OM]upgradePackageLogic执行，default pack upgrade: %s,%s, duration:%s, durationUnit:%s", newPack.getName(), newPack.getType(), duration, durationUnit));
        }
        UpgradePackDTO upgradePackDTO;
        // 处理体验版用户 原价购买专业版和高级版的逻辑，此时不改变当前套餐，活动结束可取消调用
        UpgradePackDTO trialUpgradePackDTO = dealTrialLogicUpgradePackage(oldPack, newPack, organization, duration, durationUnit);
        if (Objects.nonNull(trialUpgradePackDTO)) {
            return trialUpgradePackDTO;
        }
        Date packExpireDate = null;
        // 原套餐为试用或免费版
        if (oldPack.getType().equals(PackageTypeEnum.FREE.getType()) || oldPack.getType().equals(PackageTypeEnum.FREE_TRIAL.getType())) {
            packExpireDate = getExpireDate(new Date(), duration, durationUnit);
            // 原套餐与新套餐相同
        } else if (oldPack.getType().equals(newPack.getType())) {
            packExpireDate = getExpireDate(GrpcDateUtil.getDate(organization.getFormalExpireTime()), duration, durationUnit);
        } else {
            // 当前版本不为基础版的  不直接升级 通知销售
            String key = organization.getInner() ? RedisKeyConstant.ORDER_EMAIL_CONF_TEST : RedisKeyConstant.ORDER_EMAIL_CONF_REAL;
            // 获取销售邮箱
            List<String> toEmails = getNotifyEmails(key);
            // 如果订单支付方式为微信支付
            if (orderInfo.getPayMethod().equals(PaymentMethodEnum.PAYMENT_METHOD_WECHAT.getType())) {
                notifyConfirmPayByEmail(toEmails, organization, oldPack.getName(), newPack.getName(), orderInfo, adminUser);
            } else {
                notifyPackageUpgradeByEmail(toEmails, organization, oldPack.getName(), newPack.getName(), orderInfo, adminUser);
            }
            // 短信通知用户
            notifyCompanyPackagePaySuccessBySms(organization.getAdminPhone(), newPack.getName(), organization.getId(), "版本购买-微信支付-付款回执");
            return null;
        }
        upgradePackDTO = new UpgradePackDTO();
        upgradePackDTO.setPackageId(newPack.getId());
        upgradePackDTO.setExpireDate(packExpireDate);
        upgradePackDTO.setFormalPackageId(newPack.getId());
        upgradePackDTO.setFormalExpireDate(packExpireDate);
        return upgradePackDTO;
    }

    /**
     * 套餐升级给销售发送邮件
     *
     * @param toEmailList
     * @param organization
     * @param oldPackName
     * @param nowPackName
     * @param order
     * @param admin
     */
    private void notifyPackageUpgradeByEmail(List<String> toEmailList, Organization organization, String oldPackName, String nowPackName, OrderDTO order, User admin) {
        String subject = "【待确认】倍市得" + organization.getName() + "租户购买" + nowPackName + "版本通知";
        String packageEmailPrefix = "";
        if (settingProperties.getAppEnv().equals("production")) {
            packageEmailPrefix = "https://xm-company.idiaoyan.cn";
        } else {
            packageEmailPrefix = settingProperties.getServerProtocol() + "://www." + settingProperties.getXmServerHost();
        }
        String url = packageEmailPrefix + ORDER_MANAGER_URL_SUFFIX;
        JSONObject jsonObject = JSONObject.parseObject(order.getExtra());
        int duration = jsonObject.getIntValue(DURATION);
        String payMethod = "";
        if (Integer.valueOf(0).equals(order.getPayMethod())) {
            payMethod = "未定义";
        } else if (Integer.valueOf(1).equals(order.getPayMethod())) {
            payMethod = "微信支付";
        } else if (Integer.valueOf(2).equals(order.getPayMethod())) {
            payMethod = "支付宝支付";
        } else if (Integer.valueOf(3).equals(order.getPayMethod())) {
            payMethod = "对公转账";
        } else if (Integer.valueOf(4).equals(order.getPayMethod())) {
            payMethod = "银联支付";
        }
        String content = EmailTemplateUtil.packagePayToThePublicNotifySaleEmail(organization.getName(),
                oldPackName,
                nowPackName,
                url,
                organization.getCode(),
                duration,
                order.getTotalAmount() / 100,
                payMethod, order.getOrderNo(),
                admin.getPhone(),
                admin.getEmail());
        JavaMailSenderImpl javaMailSender = javaEmailSenderPool.getDefaultSender();
        sycExecUtil.asycnExec(() -> EmailUtil.sendMail(javaMailSender, toEmailList.toArray(new String[toEmailList.size()]), subject, content));
        // 邮件发送成功推送同步mq消息
        MsgDataDTO msgDataDTO = new MsgDataDTO();
        msgDataDTO.setContent(content);
        msgDataDTO.setName(subject);
        msgDataDTO.setOrgId(organization.getId());
        msgDataDTO.setReceiver(String.join(",", toEmailList));
        msgDataDTO.setSender("倍市得");
        msgDataDTO.setType(SendChannelEnum.EMAIL.getIndex());
        msgDataDTO.setStatus(SendStatusEnum.SENDING.getIndex());
        msgDataDTO.setSendTime(cn.hutool.core.date.DateUtil
                .format(LocalDateTime.now(), CommonConstant.SEND_TIME_FORMAT));
        omMqService.saveSycData(msgDataDTO);
    }

    /**
     * 套餐付款成功系统未自动升级订单
     *
     * @param phone
     * @param newPackName
     * @param orgId
     */
    private void notifyCompanyPackagePaySuccessBySms(String phone, String newPackName, String orgId, String notifyTitle) {
        String content = String.format(SmsTemplateUtil.PACKAGE_PAY_SUCCESS_SMS_TMPL, newPackName);
        Integer status = null;
        try {
            smsService.smsSingleSend(phone, content, cn.hutool.core.lang.ObjectId.next());
            status = CommonConstant.NOTIFY_STATUS_IS_SEND;
        } catch (Exception e) {
            log.error("[OM] send notify_company_package_upgrade_by_sms error: %s ", e);
            status = CommonConstant.NOTIFY_STATUS_SEND_FAILED;
        }
        if (isBaseline) {
            return;
        }
        // 消息同步至 系统商后台通知中心
        MsgDataDTO msgDataDTO = new MsgDataDTO();
        msgDataDTO.setContent(content);
        if (StringUtils.isNotBlank(notifyTitle)) {
            msgDataDTO.setName(notifyTitle);
        } else {
            msgDataDTO.setName("版本购买-对公转账-付款回执");
        }
        msgDataDTO.setOrgId(orgId);
        msgDataDTO.setReceiver(phone);
        msgDataDTO.setSender("");
        msgDataDTO.setType(CommonConstant.NOTIFY_TYPE_MOBILE);
        msgDataDTO.setSmsChannel(CommonConstant.NOTIFY_SMS_CHANNEL_YIMEI);
        msgDataDTO.setStatus(status);
        msgDataDTO.setSendTime(DateUtil.convertDteToString(new Date(), DateUtil.NORM_DATETIME_PATTERN));
        msgDataDTO.setTemplateId("");
        Map<String, String> param = new HashMap<>(16);
        param.put("pack_name", newPackName);
        msgDataDTO.setParams(JSON.toJSONString(param));
        omMqService.saveSycData(msgDataDTO);
    }

    /**
     * 在线支付购买套餐成功
     *
     * @param phone
     * @param newPackName
     * @param orgId
     */
    private void notifyCompanyPackageUpgradeBySms(String phone, String newPackName, String orgId) {
        String content = String.format(SmsTemplateUtil.PACKAGE_UPGRADE_SMS_TMPL, newPackName);
        Integer status = null;
        try {
            smsService.smsSingleSend(phone, content, cn.hutool.core.lang.ObjectId.next());
            status = CommonConstant.NOTIFY_STATUS_IS_SEND;
        } catch (Exception e) {
            log.error("[OM] send notifyCompanyPackageUpgradeBySms error: %s ", e);
            status = CommonConstant.NOTIFY_STATUS_SEND_FAILED;
        } finally {
            // 消息同步至 系统商后台通知中心
            MsgDataDTO msgDataDTO = new MsgDataDTO();
            msgDataDTO.setContent(content);
            msgDataDTO.setName("版本购买-微信支付-升级回执");
            msgDataDTO.setOrgId(orgId);
            msgDataDTO.setReceiver(phone);
            msgDataDTO.setSender("");
            msgDataDTO.setType(CommonConstant.NOTIFY_TYPE_MOBILE);
            msgDataDTO.setSmsChannel(CommonConstant.NOTIFY_SMS_CHANNEL_YIMEI);
            msgDataDTO.setStatus(status);
            msgDataDTO.setSendTime(DateUtil.convertDteToString(new Date(), DateUtil.NORM_DATETIME_PATTERN));
            msgDataDTO.setTemplateId("");
            Map<String, String> param = new HashMap<>(16);
            param.put("pack_name", newPackName);
            msgDataDTO.setParams(JSON.toJSONString(param));
            omMqService.saveSycData(msgDataDTO);
        }
    }

    /**
     * 正式套餐购买时，先检查试用套餐的一些逻辑
     * 购买双十一体验版的，后全款购买的用户
     * 正式套餐会自动变更为用户购买的版本，但此时生效的还是试用套餐。正式套餐的到期日=1年+剩余试用时间。
     * 活动结束可去掉调用
     * python ref: apps_mysql.user.util.utils.deal_trial_logic_upgrade_package
     *
     * @param oldPack
     * @param newPack
     * @param organization
     * @param duration
     * @param durationUnit
     * @return com.bestcem.xm.user.service.dto.order.UpgradePackDTO
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/05/08 18:39
     */
    private UpgradePackDTO dealTrialLogicUpgradePackage(UserPack oldPack, UserPack newPack, Organization organization, Integer duration, Integer durationUnit) {

        UpgradePackDTO upgradePackDTO = new UpgradePackDTO();
        Date startTime = null;
        // 检查是否购买专业体验版
        if (StringUtils.isNotBlank(organization.getTrialPackageId())) {
            UserPack trialPack = omUserPackDao.getById(organization.getTrialPackageId());
            // 条件：1.试用套餐不为空，2.名称为：专业版双十一特惠，3.试用套餐过期时间不为空，4.试用套餐过期时间>当前时间
            if (Objects.nonNull(trialPack)
                    && trialPack.getName().equals(CommonConstant.TRIAL_1111_PACK_NAME)
                    && Objects.nonNull(organization.getTrialExpireTime())
                    && GrpcDateUtil.getDate(organization.getTrialExpireTime()).after(new Date())) {
                startTime = GrpcDateUtil.getDate(organization.getTrialExpireTime());
            }
        }
        // 原套餐类型为免费版或试用版
        if (Objects.nonNull(startTime) && (oldPack.getType().equals(PackageTypeEnum.FREE.getType()) ||
                oldPack.getType().equals(PackageTypeEnum.FREE_TRIAL.getType()))) {
            // 免费版购买体验版, 后购买高级版或专业版， 不修改当前套餐
            Date packExpireDate = getExpireDate(startTime, duration, durationUnit);
            upgradePackDTO.setFormalPackageId(newPack.getId());
            upgradePackDTO.setFormalExpireDate(packExpireDate);
            return upgradePackDTO;
        } else if (Objects.nonNull(startTime) && oldPack.getType().equals(PackageTypeEnum.SENIOR.getType())) {
            // 高级版可体验专业版，不修改当前套餐
            Date packExpireDate = getExpireDate(GrpcDateUtil.getDate(organization.getFormalExpireTime()), duration, durationUnit);
            upgradePackDTO.setFormalPackageId(newPack.getId());
            upgradePackDTO.setFormalExpireDate(packExpireDate);
            return upgradePackDTO;
        }
        return null;
    }

    /**
     * 获取过期时间
     * 返回时间为：date+duration
     *
     * @param duration
     * @param durationUnit
     * @return java.util.Map<java.lang.String, java.lang.Integer>
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/05/07 16:02
     */
    private Date getExpireDate(Date date, Integer duration, Integer durationUnit) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        if (durationUnit.equals(OrderExtraDurationEnum.ORDER_EXTRA_DURATION_YEAR.getType())) {
            c.add(Calendar.YEAR, duration);
        }
        if (durationUnit.equals(OrderExtraDurationEnum.ORDER_EXTRA_DURATION_MONTH.getType())) {
            c.add(Calendar.MONTH, duration);
        }
        if (durationUnit.equals(OrderExtraDurationEnum.ORDER_EXTRA_DURATION_DAY.getType())) {
            c.add(Calendar.DAY_OF_YEAR, duration);
        }
        return c.getTime();
    }

    /**
     * 邮件通知确认线下支付
     * 调用处：1.线下订单确认支付confirmSale 2.默认套餐逻辑购买upgradePackageLogic
     *
     * @param toEmailList
     * @param organization
     * @param oldPackName
     * @param nowPackName
     * @param order
     * @param admin
     */
    private void notifyConfirmPayByEmail(List<String> toEmailList, Organization organization, String oldPackName, String nowPackName, OrderDTO order, User admin) {
        // 邮件主题：【待升级】倍市得%s租户购买%s版本通知
        String subject = String.format(OrderConstant.ORDER_CONFIRM_EMAIL_SUBJECT, organization.getName(), nowPackName);
        String url = packageEmailPrefix + ORDER_MANAGER_URL_SUFFIX;
        int duration = getOrderDuration(order);
        String payMethod = PaymentMethodEnum.getDescByType(order.getPayMethod());
        String content = EmailTemplateUtil.packageSaleConfirmPayEmail(organization.getName(),
                oldPackName,
                nowPackName,
                url,
                organization.getCode(),
                duration,
                order.getTotalAmount() / 100,
                order.getReceiptAmount() / 100,
                payMethod, order.getOrderNo(),
                admin.getPhone(),
                admin.getEmail());
        sycExecUtil.asycnExec(() -> EmailUtil.sendMail(javaEmailSenderPool.getDefaultSender(), toEmailList.toArray(new String[toEmailList.size()]), subject, content));
        // 邮件发送成功推送同步mq消息
        MsgDataDTO msgDataDTO = new MsgDataDTO();
        msgDataDTO.setContent(content);
        msgDataDTO.setName(subject);
        msgDataDTO.setOrgId(organization.getId());
        msgDataDTO.setReceiver(String.join(",", toEmailList));
        msgDataDTO.setSender("倍市得");
        msgDataDTO.setType(SendChannelEnum.EMAIL.getIndex());
        msgDataDTO.setStatus(SendStatusEnum.SENDING.getIndex());
        msgDataDTO.setSendTime(cn.hutool.core.date.DateUtil
                .format(LocalDateTime.now(), CommonConstant.SEND_TIME_FORMAT));
        omMqService.saveSycData(msgDataDTO);
    }


    /**
     * 确认升级，邮件通知
     *
     * @param toEmailList
     * @param organization
     * @param oldPackName
     * @param nowPackName
     * @param order
     * @param admin
     */
    private void notifyConfirmUpgradeByEmail(List<String> toEmailList,
                                             Organization organization,
                                             String oldPackName,
                                             String nowPackName,
                                             String duration,
                                             OrderDTO order,
                                             User admin,
                                             String upgradeStartDt,
                                             String upgradeEndDt) {
        // 邮件主题：【已升级】倍市得%s租户购买%s版本通知
        String subject = String.format(OrderConstant.ORDER_UPGRADE_EMAIL_SUBJECT, order.getPayerOrgName(), nowPackName);
        String url = packageEmailPrefix + ORDER_MANAGER_URL_SUFFIX;
        String payMethod = PaymentMethodEnum.getDescByType(order.getPayMethod());
        String content = EmailTemplateUtil.packageSaleConfirmUpgradeEmail(organization.getName(),
                oldPackName,
                nowPackName,
                url,
                organization.getCode(),
                duration,
                order.getTotalAmount() / 100,
                order.getReceiptAmount() / 100,
                payMethod, order.getOrderNo(),
                admin.getPhone(),
                admin.getEmail(),
                upgradeStartDt,
                upgradeEndDt);
        sycExecUtil.asycnExec(() -> EmailUtil.sendMail(javaEmailSenderPool.getDefaultSender(), toEmailList.toArray(new String[toEmailList.size()]), subject, content));
        // 邮件发送成功推送同步mq消息
        MsgDataDTO msgDataDTO = new MsgDataDTO();
        msgDataDTO.setContent(content);
        msgDataDTO.setName(subject);
        msgDataDTO.setOrgId(organization.getId());
        msgDataDTO.setReceiver(String.join(",", toEmailList));
        msgDataDTO.setSender("倍市得");
        msgDataDTO.setType(SendChannelEnum.EMAIL.getIndex());
        msgDataDTO.setStatus(SendStatusEnum.SENDING.getIndex());
        msgDataDTO.setSendTime(cn.hutool.core.date.DateUtil
                .format(LocalDateTime.now(), CommonConstant.SEND_TIME_FORMAT));
        omMqService.saveSycData(msgDataDTO);
    }

    /**
     * 获取通知的邮箱列表
     *
     * @param key
     * @return
     */
    private List<String> getNotifyEmails(String key) {
        List<String> emails = JSON.parseArray(redisUtil.getString(key), String.class);
        if (CollectionUtils.isEmpty(emails)) {
            return Collections.emptyList();
        }
        return emails;
    }

    /**
     * 获取订单扩展字段购买时长
     *
     * @param order
     * @return
     */
    public int getOrderDuration(OrderDTO order) {
        JSONObject jsonObject = JSONObject.parseObject(order.getExtra());
        return jsonObject.getIntValue(DURATION);
    }
}
